﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CefBinariesLoader.cs" company="Chromely Projects">
//   Copyright (c) 2017-2019 Chromely Projects
// </copyright>
// <license>
//      See the LICENSE.md file in the project root for more information.
// </license>
// ----------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Xml;
using System.Xml.Linq;
using Chromely.CefGlue.Loader;
using Chromely.Core;
using Chromely.Core.Infrastructure;
using Xilium.CefGlue;

namespace Chromely.CefGlue.BrowserWindow
{
    /// <summary>
    /// The cef binaries loader.
    /// </summary>
    public static class CefBinariesLoader
    {
        /// <summary>
        /// The chromely logo base6encoded.
        /// </summary>
        private const string ChromelyImgBase6Encoded = "";

        /// <summary>
        /// The load.
        /// </summary>
        /// <param name="config">
        /// The config.
        /// </param>
        /// <returns>
        /// The list of temporary files generated
        /// </returns>
        public static List<string> Load(IChromelyConfiguration config)
        {
            try
            {
                var platform = CefRuntime.Platform;
                var version = CefRuntime.ChromeVersion;
                Logger.Instance.Log.Info($"Running {platform} chromium {version}");

                try
                {
                    CefRuntime.Load();
                }
                catch (Exception ex)
                {
                    Logger.Instance.Log.Error(ex);
                    if (config.LoadCefBinariesIfNotFound)
                    {
                        if (config.SilentCefBinariesLoading)
                        {
                            CefLoader.Load(config.Platform);
                        }
                        else
                        {
                            return WarnUserOnLoad(config.Platform);
                        }
                    }
                    else
                    {
                        Environment.Exit(0);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Instance.Log.Error(ex);
                Environment.Exit(0);
            }

            return null;
        }

        /// <summary>
        /// The delete temp files.
        /// </summary>
        /// <param name="tempFiles">
        /// The temp files.
        /// </param>
        public static void DeleteTempFiles(List<string> tempFiles)
        {
            if (tempFiles == null || !tempFiles.Any())
            {
                return;
            }

            foreach (var file in tempFiles)
            {
                try
                {
                    File.Delete(file);
                }
                catch (Exception ex)
                {
                    Logger.Instance.Log.Error(ex);
                    throw;
                }
            }
        }

        /// <summary>
        /// The warn user on load.
        /// </summary>
        /// <returns>
        /// The list of temporary files generated
        /// </returns>
        private static List<string> WarnUserOnLoad(ChromelyPlatform platform)
        {
            var tempFiles = new List<string>();

            try
            {
                var stopwatch = new Stopwatch();
                stopwatch.Start();

                var startTempFile = LaunchStartPage();
                tempFiles.Add(startTempFile);

                CefLoader.Load(platform);

                stopwatch.Stop();
                var competedTempFile = LaunchCompletedPage($"Time elapsed: {stopwatch.Elapsed}.");

                if (competedTempFile != null)
                {
                    tempFiles.Add(competedTempFile);
                }

                Thread.Sleep(TimeSpan.FromSeconds(2));
            }
            catch (Exception ex)
            {
                Logger.Instance.Log.Error(ex);
                var onErrorTempFile = LaunchErrorPage(ex);
                tempFiles.Add(onErrorTempFile);
                Environment.Exit(0);
            }

            return tempFiles;
        }

        /// <summary>
        /// The launch start page.
        /// </summary>
        /// <returns>
        /// The temporary file created.
        /// </returns>
        private static string LaunchStartPage()
        {
            var message = new Tuple<string, string, string>(
                "CEF binaries download started.",
                "Note that depending on your network, this might take up to 4 minutes to complete.",
                "Please wait...");

            return LaunchHtmlWarningPage(message);
        }

        /// <summary>
        /// The launch completed page.
        /// </summary>
        /// <param name="durationInfo">
        /// The duration info.
        /// </param>
        /// <returns>
        /// The temporary file created.
        /// </returns>
        private static string LaunchCompletedPage(string durationInfo)
        {
            var message = new Tuple<string, string, string>(
                "CEF binaries download completed successfully.",
                durationInfo,
                "Please close.");

            return LaunchHtmlWarningPage(message);
        }

        /// <summary>
        /// The launch error page.
        /// </summary>
        /// <param name="ex">
        /// The exception.
        /// </param>
        /// <returns>
        /// The temporary file created.
        /// </returns>
        private static string LaunchErrorPage(Exception ex)
        {
            var message = new Tuple<string, string, string>(
                "CEF binaries download completed with error.",
                "Error message: " + ex.Message,
                "Please close.");

            return LaunchHtmlWarningPage(message);
        }

        /// <summary>
        /// The launch html warning page.
        /// </summary>
        /// <param name="message">
        /// The message.
        /// </param>
        /// <returns>
        /// The temporary file created.
        /// </returns>
        private static string LaunchHtmlWarningPage(Tuple<string, string, string> message)
        {
            try
            {
                var xDocument = new XDocument(
                    new XDocumentType("html", null, null, null),
                    new XElement(
                        "html",
                                    new XAttribute("lang", "en"),
                                    new XElement(
                                        "head",
                                        new XElement(
                                            "meta",
                                            new XAttribute("http-equiv", "content-type"),
                                            new XAttribute("content", "text/html"),
                                            new XAttribute("charset", "utf-8")),
                                        new XElement("title", "Chromely CEF Binaries Download"),
                                        new XElement(
                                            "style",
                                            new XAttribute("type", "text/css"),
                                            "#box_1 { position: absolute; top: 75px; right: 75px; bottom: 75px; left: 75px; } #box_2 { position: absolute; top:150px; right: 150px; bottom: 150px; left: 150px; }")),
                                    new XElement(
                                        "body",
                                        new XElement("div", new XAttribute("id", "box_1")),
                                        new XElement(
                                            "div",
                                            new XAttribute("id", "box_2"),
                                            new XAttribute("align", "center")),
                                        new XElement(
                                            "img",
                                            new XAttribute("src", ChromelyImgBase6Encoded)),
                                        new XElement("h1", "chromely"),
                                        new XElement("div", message.Item1),
                                        new XElement("div", message.Item2),
                                        new XElement("div", message.Item3),
                                        new XElement("p", string.Empty),
                                        new XElement("div", "For more info - ", new XElement("a", "Chromely Apps", new XAttribute("href", "https://github.com/chromelyapps/Chromely"))),
                                        new XElement("p", string.Empty),
                                        new XElement(
                                            "input",
                                            new XAttribute("type", "button"),
                                            new XAttribute("value", "Close"),
                                            new XAttribute("onclick", "window.close()")))));

                var settings = new XmlWriterSettings
                {
                    OmitXmlDeclaration = true,
                    Indent = true,
                    IndentChars = "\t"
                };

                var htmlFileName = Guid.NewGuid() + ".html";

                using (var writer = XmlWriter.Create(htmlFileName, settings))
                {
                    xDocument.WriteTo(writer);
                }

                if (CefRuntime.Platform == CefRuntimePlatform.Linux)
                {
                    Process.Start("xdg-open", htmlFileName);
                }
                else if (CefRuntime.Platform == CefRuntimePlatform.MacOSX)
                {
                    Process.Start("open", htmlFileName);
                }
                else
                {
                    try
                    {
                        Process.Start(htmlFileName);
                    }
                    catch 
                    {
                        try
                        {
                            Process.Start(@"cmd.exe ", @"/c " + htmlFileName);
                        }
                        catch
                        {
                            // ignored
                        }
                    }
                }

                return htmlFileName;
            }
            catch (Exception e)
            {
                Logger.Instance.Log.Error(e);
                Console.WriteLine(message);
            }

            return null;
        }
    }
}
